﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoreEx.Database.Metadata;
using LinFu.IoC.Configuration;
using CoreEx.DynamicInvoker;
namespace CoreEx.Database.Persistence.Implementation
{
    [Implements(typeof(IComparer<IObjectState>))]
    public class ObjectStateComparer : IComparer<IObjectState>
    {
        
        public ITypeMappingRepository MappingRepository { get; private set; }
         

        public int Compare(IObjectState x, IObjectState y)
        {
           
            
            
            
            if (x.State == StateType.Deleted && y.State != StateType.Deleted)
                return -1;

            if (x.State != StateType.Deleted && y.State == StateType.Deleted)
                return 1;


            if (x.State == StateType.NewModified && y.State != StateType.NewModified)
                return -1;

            if (x.State != StateType.NewModified && y.State == StateType.NewModified)
                return 1;


            if (x.State == StateType.Deleted && y.State == StateType.Deleted)
            {
                var result = CompareDeleted(x, y);
                if (result != 0)
                    return result;
            }

            if (x.State == StateType.NewModified && y.State == StateType.NewModified)
            {
                var result =  CompareInsertUpdate(x, y);
                if (result != 0)
                    return result;
            }

            if (x.State == StateType.Modified && y.State == StateType.Modified)
            {
                var result =  CompareInsertUpdate(x, y);
                if (result != 0)
                    return result;
            }


             //Self reference
            if (IsSelfReferencing(x,y))
            {
                if (x.State == StateType.Deleted && y.State == StateType.Deleted)
                {
                    var parentReference = x.GetType().GetProperties().Where(p => p.PropertyType == y.GetType()).FirstOrDefault();            
                    if (parentReference != null)
                    {
                        var value = parentReference.DynamicInvoke(x);
                        if (value == null)
                            return 1;
                        if (value == y.Target)
                            return -1;
                        
                        return 0;
                    }
                }
            }

            return 0;
        }

        


        private bool IsSelfReferencing(IObjectState x, IObjectState y)
        {
            var xType = x.GetType();
            var yType = y.GetType();

            if (xType != yType)
                return false;

            var xTypeMapping = MappingRepository[xType];
            var yTypeMapping = MappingRepository[xType];

            if (xTypeMapping.ColumnMappings.Values.Count(cm => cm.Property.PropertyType == yType) > 0)
                return true;

            if (yTypeMapping.ColumnMappings.Values.Count(cm => cm.Property.PropertyType == xType) > 0)
                return true;
            return false;
        }


        private int CompareDeleted(IObjectState x, IObjectState y)
        {
            return -1;
        }

        private int CompareInsertUpdate(IObjectState x, IObjectState y)
        {
            return -1;
        }

    }
}
